/*
 * 多进程结构子进程库
 */

package child

import (
	"errors"
	"net"
	"os"
	"strconv"
	"time"

	"sieve_engine/lib/app"
	"sieve_engine/lib/xconn"
)

var child *Child

type Child struct {
	id         string
	sock       string
	msgHandler func(data []byte) []byte
	conn       *xconn.Conn
}

func init() {
	child = &Child{id: os.Getenv("__MP_CHILD_ID__"), sock: os.Getenv("__MP_PARENT_SOCK__")}

	go func() {
		for {
			if os.Getppid() == 1 {
				app.SafeExit()
			}
			time.Sleep(time.Second)
		}
	}()
}

func HandleMessage(handler func(data []byte) []byte) error {
	if child.id == "" {
		return errors.New("process was not run by parent")
	}
	if child.sock == "" {
		return errors.New("parent did not open socket")
	}
	if child.msgHandler != nil {
		return errors.New("already set message handler")
	}
	child.msgHandler = handler

	return connect()
}

func connect() error {
	conn, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: child.sock, Net: "unix"})
	if err != nil {
		return err
	}
	c, err := xconn.NewConn(conn, &xconn.Config{OnInit: func(rw xconn.RawRW) error {
		return rw.Write([]byte(strconv.Itoa(os.Getpid())))
	}})
	if err != nil {
		return err
	}
	c.Handle(child.msgHandler)
	child.conn = c
	return nil
}

func Post(msg []byte) error {
	if child.conn == nil {
		return errors.New("child has no connection")
	}
	return child.conn.Post(msg)
}

func Request(data []byte) ([]byte, error) {
	if child.conn == nil {
		return nil, errors.New("child has no connection")
	}
	return child.conn.Request(data)
}
